#!/bin/bash
## StatsLib tests config script

function print_help
{ 
    # echo "" ;
    echo -e "\x1B[32mStatsLib Tests configure options\033[0m" >&2 ;
    echo "" ;
    echo "-c    Coverage build" ;
    echo "-g    Debugging build (optimization flags set to: -O0 -g)" ;
    echo "-h    Print help" ;
    echo "-i    StatsLib install path (default: build directory)" ;
    echo "-l    Enable wrappers for a linear algebra library" ;
    echo "        Examples: -l arma, -l blaze, or -l eigen" ;
    echo "-m    Specify the BLAS and Lapack libraries to link against" ; 
    echo "        Examples: -m \"-lopenblas\" or -m \"-framework Accelerate\"" ;
    echo "-o    Compiler optimization options; defaults to:" ;
    echo "        -O3 -march=native -ffp-contract=fast" ;
    echo "-p    Enable OpenMP parallelization features" ;
    echo "-s    Enable std::vector tests" ;
    echo "-v    Set verbose print level: 0, 1, or 2" ;
    echo "" ;
}

while getopts hcgil:m:o:psv: option; do
    case "${option}" in
        h) print_help; exit 2;;
        c) STATS_COVERAGE_BUILD="y";;
        g) STATS_DEBUG_BUILD="y";;
        i) STATS_INSTALL_PATH=${OPTARG};;
        l) STATS_LINEAR_ALG_LIB=${OPTARG};;
        m) STATS_MATRIX_OPS=${OPTARG};;
        o) STATS_OPT=${OPTARG};;
        p) STATS_ENABLE_PARALLEL="y";;
        s) STATS_ENABLE_STDVEC="y";;
        v) STATS_VERBOSE_PRINT=${OPTARG};;
        ?) print_help; exit 2;;
    esac
done

# compiler checks

CXX_STD="-std=c++11"

if [ -z ${CXX+x} ]; then 
    CXX=g++
fi

#

echo ""
echo -e "\x1B[32mStatsLib Test Configuration...\033[0m" >&2 ;
echo ""

IS_DARWIN=$($CXX -dumpmachine 2>&1 | grep -i -c "darwin")
GCC_COMPILER=$($CXX --version 2>&1 | grep -i -c -E "gcc")
APPLE_COMPILER=$($CXX --version 2>&1 | grep -i -c -E 'apple llvm')

# get working directory
WDIR=${PWD}

# Matrix Linear Algebra Libraries
STATS_MATLIB_FLAGS=
STATS_MATLIB_PATH="."

# look for GCEM
if [ -z ${GCEM_INCLUDE_PATH+x} ]; then
    echo -e "  \x1B[31m- error: cannot find the GCEM library header files.\033[0m" >&2 ;
    echo -e "  \x1B[31m-        Please set the GCEM_INCLUDE_PATH variable to the directory of gcem.hpp. \033[0m" >&2 ;
    echo -e "  \x1B[31m-        Exiting.\033[0m" >&2 ;
    echo ""
    exit 1
fi

# look for Armadillo
if [[ "${STATS_LINEAR_ALG_LIB}" == "arma" ]]; then
    if [ -z ${ARMA_INCLUDE_PATH+x} ]; then 
        
        declare -a ARMA_DIRS=("${WDIR}/../../include" "/usr/include" "/usr/local/include" "/opt/include" "/opt/local/include")
        ARMA_INCLUDE_PATH=

        for i in "${ARMA_DIRS[@]}"; do
            if [ -f "$i"/armadillo ]; then 
                ARMA_INCLUDE_PATH="$i"
                break
            fi
        done

        if [[ $ARMA_INCLUDE_PATH == "" ]]; then
            echo -e "  \x1B[31m- error: cannot find the Armadillo library header files. Exiting.\033[0m" >&2 ;
            echo ""
            exit 1
        fi
    fi

    STATS_MATLIB_FLAGS="-DSTATS_ENABLE_ARMA_WRAPPERS -DARMA_NO_DEBUG"
    STATS_MATLIB_PATH=$ARMA_INCLUDE_PATH
elif [[ "${STATS_LINEAR_ALG_LIB}" == "blaze" ]]; then
    STATS_MATLIB_FLAGS="-DSTATS_ENABLE_BLAZE_WRAPPERS"
    STATS_MATLIB_PATH=$BLAZE_INCLUDE_PATH
    CXX_STD="-std=c++14"
elif [[ "${STATS_LINEAR_ALG_LIB}" == "eigen" ]]; then
    STATS_MATLIB_FLAGS="-DSTATS_ENABLE_EIGEN_WRAPPERS"
    STATS_MATLIB_PATH=$EIGEN_INCLUDE_PATH
else
    STATS_LINEAR_ALG_LIB="none"
fi

#

if [[ "${STATS_ENABLE_STDVEC}" == "y" ]]; then
    STATS_MATLIB_FLAGS="-DSTATS_ENABLE_STDVEC_WRAPPERS ${STATS_MATLIB_FLAGS}"
fi

#
if [[ !(-z ${STATS_VERBOSE_PRINT+x}) ]]; then
    STATS_MATLIB_FLAGS="-DTEST_PRINT_LEVEL=${STATS_VERBOSE_PRINT} ${STATS_MATLIB_FLAGS}"
fi

# set optimization flags

if [[ "${STATS_COVERAGE_BUILD}" == "y" ]]; then 
    if [ "$GCC_COMPILER" -eq "1" ]; then
        STATS_OPT_FLAGS="-g -O0 --coverage -fno-inline -fno-inline-small-functions -fno-default-inline -DSTATS_DONT_USE_OPENMP"
    else # clang:
        STATS_OPT_FLAGS="-g -O0 --coverage -fno-inline -DSTATS_DONT_USE_OPENMP"
    fi
elif [[ "${STATS_DEBUG_BUILD}" == "y" ]]; then
    STATS_OPT_FLAGS="-g -O0 -DSTATS_DONT_USE_OPENMP"
else
    if [[ "${STATS_OPT}" == "" ]]; then
        STATS_OPT_FLAGS="-O3 -march=native -ffp-contract=fast"
    else
        STATS_OPT_FLAGS="${STATS_OPT}"
    fi

    if [[ "${STATS_ENABLE_PARALLEL}" == "y" ]]; then
        STATS_OPT_FLAGS="${STATS_OPT_FLAGS} -fopenmp"
    fi
fi

STATS_WARN_FLAGS="-Wall -Wextra"

# dev build

if [[ "${STATS_INSTALL_PATH}" == "" ]]; then
    cd ../..
    STATS_INSTALL_PATH=${PWD}
    STATS_INSTALL_INCLUDE_PATH=${PWD}/include
    cd ${WDIR}
else
    STATS_INSTALL_INCLUDE_PATH="${STATS_INSTALL_PATH}/include"
fi

# BLAS and LAPACK settings

if [[ !(-z ${STATS_MATRIX_OPS+x}) ]]; then
    STATS_BLAS_LAPACK="${STATS_MATRIX_OPS}"
else
    if [[ $OSTYPE == darwin* ]] ; then
        STATS_BLAS_LAPACK="-framework Accelerate"
    else
        STATS_BLAS_LAPACK="-lblas -llapack"
    fi
fi

# final optimization checks

if [ "$IS_DARWIN" -eq "1" ] && [ "$GCC_COMPILER" -eq "1" ]; then
    STATS_OPT_FLAGS="-Wa,-q ${STATS_OPT_FLAGS}"
fi

#
# final print:

echo "  - OS:            ${OSTYPE}"
echo "  - C++ compiler:  ${CXX}"

if [[ "${STATS_COVERAGE_BUILD}" == "y" ]]; then
    echo "  - Build version: coverage"
elif [[ "${STATS_DEBUG_BUILD}" == "y" ]]; then
    echo "  - Build version: debug"
else
    echo "  - Build version: standard"
fi

echo ""

echo "  - GCEM_INCLUDE_PATH set to:"
echo "    ${GCEM_INCLUDE_PATH}"

echo ""

if [[ "${STATS_ENABLE_STDVEC}" == "y" ]]; then
    echo -e "  - std::vector tests: \x1B[32menabled\033[0m" >&2 ;
else
    echo -e "  - std::vector tests: \x1B[31mdisabled\033[0m" >&2 ;
fi

echo ""

echo "  - STATS_LINEAR_ALG_LIB set to: ${STATS_LINEAR_ALG_LIB}"
if [[ "${STATS_LINEAR_ALG_LIB}" != "none" ]]; then 
echo "  - STATS_MATLIB_PATH set to:"
echo "    ${STATS_MATLIB_PATH}"
echo "  - BLAS and Lapack libraries set to:"
echo "    ${STATS_BLAS_LAPACK}"
fi

echo ""

if [[ "${STATS_ENABLE_PARALLEL}" == "y" ]]; then
    echo -e "  - OpenMP features: \x1B[32menabled\033[0m" >&2 ;
else
    echo -e "  - OpenMP features: \x1B[31mdisabled\033[0m" >&2 ;
fi

echo "  - Optimization flags:"
echo "    ${STATS_OPT_FLAGS}"

echo ""

echo "  - StatsLib install path:"
echo "    ${STATS_INSTALL_PATH}"

echo ""
echo "  - Additional notes:"

if [ "$APPLE_COMPILER" -eq "1" ] && [[ "${STATS_ENABLE_PARALLEL}" == "y" ]]; then
    echo -e "    \x1B[31m- You have enabled OpenMP, but your C++ compiler does not\033[0m" >&2 ;
    echo -e "    \x1B[31m  support this feature!\033[0m" >&2 ;
fi

if [ "$IS_DARWIN" -eq "1" ] && [ "$GCC_COMPILER" -eq "1" ]; then
    echo "    - To enable AVX features, your compiler will use the Apple LLVM"
    echo "      assembler"
fi

echo ""
echo -e "\x1B[32mConfiguration completed. Generating Makefile... \c\033[0m" >&2 ;

sed -e "s|@CXX@|${CXX}|" \
    -e "s|@CXX_STD@|${CXX_STD}|" \
    -e "s|@STATS_MATLIB_FLAGS@|${STATS_MATLIB_FLAGS}|" \
    -e "s|@STATS_MATLIB_PATH@|${STATS_MATLIB_PATH}|" \
    -e "s|@STATS_BLAS_LAPACK@|${STATS_BLAS_LAPACK}|" \
    -e "s|@STATS_WARN_FLAGS@|${STATS_WARN_FLAGS}|" \
    -e "s|@STATS_OPT_FLAGS@|${STATS_OPT_FLAGS}|" \
    -e "s|@GCEM_INCLUDE_PATH@|${GCEM_INCLUDE_PATH}|" \
    -e "s|@STATS_INSTALL_INCLUDE_PATH@|${STATS_INSTALL_INCLUDE_PATH}|" \
    Makefile.in > Makefile

echo -e "\x1B[32mdone.\033[0m" >&2 ;
echo ""

